"""
策略师智能体
负责制定投资策略、资产配置和风险管理
"""
from typing import List, Dict, Any
from langchain.agents import Tool
from loguru import logger

from agents.base_agent import BaseInvestmentAgent
from utils.portfolio_management import optimize_portfolio, calculate_risk_metrics

class StrategyAdvisor(BaseInvestmentAgent):
    """投资策略顾问智能体"""
    
    def __init__(self, verbose: bool = False):
        """初始化投资策略顾问智能体"""
        
        name = "王哲宇"
        role = "首席策略顾问"
        goal = "制定最优投资策略和资产配置方案，平衡收益与风险"
        backstory = """
        你是王哲宇，一位资深投资策略专家，拥有20年投资经验和哈佛商学院MBA学位。
        你曾在国际知名对冲基金担任投资总监，经历过多次金融危机并成功带领团队穿越周期。
        你擅长宏观策略研判和资产配置优化，对市场周期和行业轮动有深刻洞察。
        你的投资理念强调风险管理和长期复合收益，注重绝对收益而非相对基准。
        """
        
        # 创建策略顾问专用工具
        tools = [
            Tool(
                name="develop_investment_strategy",
                func=self._develop_investment_strategy,
                description="基于市场环境和分析报告制定投资策略"
            ),
            Tool(
                name="asset_allocation",
                func=self._optimize_asset_allocation,
                description="优化资产配置比例，平衡各行业和个股权重"
            ),
            Tool(
                name="risk_management",
                func=self._manage_risk,
                description="评估投资组合风险，制定风险控制措施"
            )
        ]
        tools_dict = [tool.dict() for tool in tools]
        super().__init__(name, role, goal, backstory, tools_dict, verbose)
        logger.info(f"投资策略顾问 {name} 初始化完成")
    
    def _develop_investment_strategy(self, market_environment: Dict[str, Any]) -> Dict[str, Any]:
        """
        制定投资策略
        
        参数:
            market_environment: 市场环境数据，包含趋势、情绪等信息
            
        返回:
            投资策略方案
        """
        logger.info(f"基于市场环境制定投资策略: {market_environment}")
        
        # 提取市场关键信息
        trend = market_environment.get("trend", {}).get("trend_direction", "盘整")
        strength = market_environment.get("trend", {}).get("strength", 50)
        sentiment = market_environment.get("sentiment", {}).get("fear_greed", 50)
        volatility = market_environment.get("sentiment", {}).get("volatility", 20)
        
        # 确定策略类型
        strategy_type = "balanced_growth"  # 默认平衡增长
        if trend == "上涨" and strength > 70 and sentiment > 60:
            strategy_type = "aggressive_growth"
        elif trend == "上涨" and strength > 50:
            strategy_type = "moderate_growth"
        elif trend == "下跌" and strength > 70 and sentiment < 40:
            strategy_type = "defensive"
        elif trend == "下跌" and strength > 50:
            strategy_type = "value_oriented"
        elif volatility > 30:
            strategy_type = "low_volatility"
        
        # 确定重点关注行业
        focus_sectors = ["科技", "消费", "医疗"]  # 默认关注
        if strategy_type == "aggressive_growth":
            focus_sectors = ["科技", "新能源", "半导体"]
        elif strategy_type == "moderate_growth":
            focus_sectors = ["科技", "消费", "高端制造"]
        elif strategy_type == "defensive":
            focus_sectors = ["公用事业", "必需消费", "医疗"]
        elif strategy_type == "value_oriented":
            focus_sectors = ["金融", "基建", "传统能源"]
        elif strategy_type == "low_volatility":
            focus_sectors = ["公用事业", "必需消费", "金融"]
            
        # 确定仓位管理策略
        position_sizing = "moderate"  # 默认中等仓位
        if strategy_type == "aggressive_growth":
            position_sizing = "aggressive"
        elif strategy_type == "defensive":
            position_sizing = "conservative"
            
        # 确定对冲策略
        hedging_strategy = "none"  # 默认无对冲
        if strategy_type == "defensive" or volatility > 25:
            hedging_strategy = "partial_index_hedge"
        elif trend == "下跌" and strength > 60:
            hedging_strategy = "full_index_hedge"
            
        return {
            "strategy_type": strategy_type,
            "focus_sectors": focus_sectors,
            "position_sizing": position_sizing,
            "hedging_strategy": hedging_strategy
        }
    
    def _optimize_asset_allocation(self, portfolio_data: Dict[str, Any]) -> Dict[str, float]:
        """
        优化资产配置
        
        参数:
            portfolio_data: 投资组合数据
            
        返回:
            优化后的资产配置比例
        """
        logger.info("优化资产配置")
        # 调用投资组合优化函数
        return optimize_portfolio(portfolio_data)
    
    def _manage_risk(self, portfolio_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        风险管理
        
        参数:
            portfolio_data: 投资组合数据，包含持仓、市值等
            
        返回:
            风险评估和控制建议
        """
        logger.info("执行风险管理")
        
        # 检查输入数据
        if not portfolio_data or "positions" not in portfolio_data:
            logger.warning("缺少投资组合数据，无法进行风险管理")
            return {
                "metrics": {},
                "risk_level": "unknown",
                "stop_loss_recommendations": {},
                "diversification_advice": "数据不足，无法提供建议"
            }
            
        # 调用风险指标计算函数
        try:
            risk_metrics = calculate_risk_metrics(portfolio_data)
        except Exception as e:
            logger.error(f"计算风险指标失败: {e}")
            risk_metrics = {
                "volatility": None,
                "beta": None,
                "sharpe_ratio": None,
                "max_drawdown": None,
                "value_at_risk": None
            }
            
        # 评估风险水平
        risk_level = "moderate"  # 默认中等风险
        volatility = risk_metrics.get("volatility")
        max_drawdown = risk_metrics.get("max_drawdown")
        
        if volatility is not None and max_drawdown is not None:
            if volatility > 0.25 or max_drawdown > 0.20:
                risk_level = "high"
            elif volatility < 0.15 and max_drawdown < 0.10:
                risk_level = "low"
        elif volatility is not None:
            if volatility > 0.25:
                risk_level = "high"
            elif volatility < 0.15:
                risk_level = "low"
        elif max_drawdown is not None:
            if max_drawdown > 0.20:
                risk_level = "high"
            elif max_drawdown < 0.10:
                risk_level = "low"
                
        # 制定止损建议
        stop_loss_recommendations = {
            "market_wide": 0.10,  # 默认市场整体止损线
            "individual_stocks": 0.20  # 默认个股止损线
        }
        if risk_level == "high":
            stop_loss_recommendations["market_wide"] = 0.07
            stop_loss_recommendations["individual_stocks"] = 0.15
        elif risk_level == "low":
            stop_loss_recommendations["market_wide"] = 0.12
            stop_loss_recommendations["individual_stocks"] = 0.25
            
        # 制定分散化建议
        diversification_advice = "当前分散化程度适中。"
        # 可以在这里添加更复杂的逻辑，例如分析行业集中度、个股集中度等
        # 例如，如果某个行业的权重过高：
        # sector_weights = calculate_sector_weights(portfolio_data)
        # max_sector_weight = max(sector_weights.values()) if sector_weights else 0
        # if max_sector_weight > 0.35:
        #     diversification_advice = f"行业集中度较高 ({max_sector_weight:.1%})，建议降低权重最高的行业配置。"
        
        # 示例：简单检查持仓数量
        num_positions = len(portfolio_data.get("positions", []))
        if num_positions < 10:
            diversification_advice = f"持仓数量较少 ({num_positions}只)，建议增加持仓数量以分散风险。"
        elif num_positions > 30:
            diversification_advice = f"持仓数量较多 ({num_positions}只)，可能导致管理难度增加，建议适当集中。"
            
        return {
            "metrics": risk_metrics,
            "risk_level": risk_level,
            "stop_loss_recommendations": stop_loss_recommendations,
            "diversification_advice": diversification_advice
        }


class PortfolioManager(BaseInvestmentAgent):
    """投资组合管理者智能体"""
    
    def __init__(self, verbose: bool = False):
        """初始化投资组合管理者智能体"""
        
        name = "赵建国"
        role = "投资组合管理总监"
        goal = "执行投资决策，优化持仓结构，追踪投资表现"
        backstory = """
        你是赵建国，一位经验丰富的投资组合管理者，拥有15年A股实战经验。
        你精通量化交易和技术分析，在不同市场环境下均有出色表现。
        你在管理大型基金和高净值客户资产方面拥有丰富经验，注重风险控制。
        你的投资风格兼具灵活性和纪律性，善于在策略框架内做出战术性调整。
        """
        
        # 创建投资组合管理者专用工具
        tools = [
            Tool(
                name="portfolio_construction",
                func=self._construct_portfolio,
                description="构建投资组合，确定各个股票的具体持仓比例"
            ),
            Tool(
                name="trade_execution",
                func=self._execute_trades,
                description="执行交易决策，包括买入和卖出操作"
            ),
            Tool(
                name="portfolio_monitoring",
                func=self._monitor_portfolio,
                description="监控投资组合表现，跟踪收益和风险指标"
            )
        ]
        tools_dict = [tool.dict() for tool in tools]
        super().__init__(name, role, goal, backstory, tools_dict, verbose)
        logger.info(f"投资组合管理者 {name} 初始化完成")
    
    def _construct_portfolio(self, strategy: Dict[str, Any], stock_pool: List[Dict[str, Any]]) -> Dict[str, float]:
        """
        构建投资组合
        
        参数:
            strategy: 投资策略，包含策略类型、重点行业等
            stock_pool: 股票池，包含股票代码、评分、行业等信息
            
        返回:
            投资组合配置（股票代码:权重）
        """
        logger.info(f"根据策略构建投资组合: {strategy}")
        
        if not stock_pool:
            logger.warning("股票池为空，无法构建投资组合")
            return {}
            
        # 提取策略信息
        strategy_type = strategy.get("strategy_type", "balanced_growth")
        focus_sectors = strategy.get("focus_sectors", [])
        position_sizing = strategy.get("position_sizing", "moderate")
        
        # 根据策略筛选股票
        selected_stocks = []
        
        # 优先选择重点行业的股票
        if focus_sectors:
            for stock in stock_pool:
                if stock.get("industry") in focus_sectors:
                    selected_stocks.append(stock)
                    
        # 如果重点行业股票不足，补充其他高分股票
        if len(selected_stocks) < 10: # 假设目标持仓数量为10-20只
            # 按评分排序股票池
            sorted_pool = sorted(stock_pool, key=lambda x: x.get("rating", 0), reverse=True)
            for stock in sorted_pool:
                # 确保不重复添加
                if stock.get("code") not in [s.get("code") for s in selected_stocks] and len(selected_stocks) < 15:
                    selected_stocks.append(stock)
                    
        # 如果仍然没有选出股票，返回空组合
        if not selected_stocks:
            logger.warning("未能根据策略选出股票")
            return {}
            
        # 确定组合权重
        portfolio_weights = {}
        num_stocks = len(selected_stocks)
        
        # 基础权重
        base_weight = 1.0 / num_stocks
        
        # 根据评分调整权重
        total_rating = sum(stock.get("rating", 3) for stock in selected_stocks) # 默认评分为3
        
        # 防止 total_rating 为 0
        if total_rating == 0:
            logger.warning("股票池中所有股票评分为0，使用等权重分配")
            for stock in selected_stocks:
                stock_code = stock.get("code")
                if stock_code:
                    portfolio_weights[stock_code] = base_weight
            return portfolio_weights

        for stock in selected_stocks:
            stock_code = stock.get("code")
            if not stock_code:
                continue
                
            rating = stock.get("rating", 3)
            
            # 评分越高，权重越高
            # 避免除零错误
            rating_ratio = rating / (total_rating / num_stocks) if (total_rating / num_stocks) != 0 else 1
            adjusted_weight = base_weight * rating_ratio
            
            # 根据仓位管理策略调整
            if position_sizing == "aggressive":
                # 放大高分股权重
                if rating > 4:
                    adjusted_weight *= 1.2
                elif rating < 3:
                    adjusted_weight *= 0.8
            elif position_sizing == "conservative":
                # 缩小高分股权重，增加低分股权重，更均衡
                if rating > 4:
                    adjusted_weight *= 0.8
                elif rating < 3:
                    adjusted_weight *= 1.2
                    
            portfolio_weights[stock_code] = adjusted_weight
            
        # 归一化权重，确保总和为1
        total_weight = sum(portfolio_weights.values())
        if total_weight > 0:
            portfolio_weights = {code: weight / total_weight for code, weight in portfolio_weights.items()}
            
        # 限制个股最大权重
        max_single_stock_weight = 0.15 if position_sizing != "aggressive" else 0.20
        portfolio_weights = self._limit_max_weight(portfolio_weights, max_single_stock_weight)
        
        logger.info(f"构建完成的投资组合包含 {len(portfolio_weights)} 只股票")
        return portfolio_weights
        
    def _limit_max_weight(self, weights: Dict[str, float], max_weight: float) -> Dict[str, float]:
        """限制个股最大权重，并将超额部分按比例分配给其他股票"""
        
        # 迭代调整权重，直到没有股票超过最大权重限制
        while True:
            exceeded_weight = 0
            num_under_limit = 0
            codes_under_limit = []
            
            # 找出超限的股票和未超限的股票
            for code, weight in weights.items():
                if weight > max_weight:
                    exceeded_weight += (weight - max_weight)
                    weights[code] = max_weight # 直接设置为最大权重
                else:
                    num_under_limit += 1
                    codes_under_limit.append(code)
                    
            # 如果没有超限或没有可分配的股票，结束迭代
            if exceeded_weight == 0 or num_under_limit == 0:
                break
                
            # 将超额权重按比例分配给未超限的股票
            weight_to_add = exceeded_weight / num_under_limit
            for code in codes_under_limit:
                weights[code] += weight_to_add
                
        # 最后再次归一化，处理可能的浮点数误差
        total_new_weight = sum(weights.values())
        if total_new_weight > 0:
            weights = {code: weight / total_new_weight for code, weight in weights.items()}
            
        return weights
    
    def _execute_trades(self, trades: List[Dict[str, Any]]) -> Dict[str, Any]:
        """
        执行交易
        
        参数:
            trades: 交易列表，包含交易指令 (buy/sell), 股票代码, 数量, 价格等
            
        返回:
            交易执行结果，包含成功和失败的交易记录
        """
        logger.info(f"执行交易: {len(trades)} 笔指令")
        
        if not trades:
            logger.warning("交易列表为空，无需执行")
            return {"success": True, "executed_trades": []}
            
        executed_trades = []
        failed_trades = []
        
        for trade in trades:
            if not all(key in trade for key in ["instruction", "stock_code", "quantity", "price"]):
                logger.error(f"交易指令格式错误: {trade}")
                failed_trades.append({"trade": trade, "reason": "指令格式错误"})
                continue
                
            instruction = trade["instruction"]
            stock_code = trade["stock_code"]
            quantity = trade["quantity"]
            price = trade["price"]
            
            if instruction not in ["buy", "sell"]:
                logger.error(f"不支持的交易指令: {instruction}")
                failed_trades.append({"trade": trade, "reason": "不支持的指令类型"})
                continue
                
            if not isinstance(quantity, int) or quantity <= 0:
                logger.error(f"交易数量无效: {quantity}")
                failed_trades.append({"trade": trade, "reason": "无效的交易数量"})
                continue
                
            if not isinstance(price, (int, float)) or price <= 0:
                logger.error(f"交易价格无效: {price}")
                failed_trades.append({"trade": trade, "reason": "无效的交易价格"})
                continue
                
            # 模拟交易执行 -  实际交易执行需要对接broker API
            try:
                # 假设交易执行成功
                executed_price = price # 模拟以指定价格成交
                execution_timestamp = "2023-01-01 10:00:00" # 实际应使用当前时间
                
                executed_trade = {
                    "instruction": instruction,
                    "stock_code": stock_code,
                    "quantity": quantity,
                    "price": price,
                    "executed_price": executed_price,
                    "execution_timestamp": execution_timestamp,
                    "status": "success"
                }
                executed_trades.append(executed_trade)
                logger.info(f"交易执行成功: {executed_trade}")
                
            except Exception as e:
                logger.error(f"交易执行失败: {trade}, 错误信息: {e}")
                failed_trades.append({"trade": trade, "reason": str(e)})
                
        result = {
            "success": len(failed_trades) == 0,
            "executed_trades": executed_trades,
            "failed_trades": failed_trades
        }
        logger.info(f"交易执行结果汇总: 成功 {len(executed_trades)} 笔, 失败 {len(failed_trades)} 笔")
        return result
    
    def _monitor_portfolio(self, portfolio: Dict[str, float]) -> Dict[str, Any]:
        """
        监控投资组合
        
        参数:
            portfolio: 投资组合配置
            
        返回:
            投资组合监控报告
        """
        logger.info("开始监控投资组合表现")
        
        if not portfolio:
            logger.warning("投资组合为空，无法监控")
            return {
                "total_value": 0,
                "daily_return": 0,
                "total_return": 0,
                "volatility": 0,
                "sharpe_ratio": 0,
                "top_performers": [],
                "underperformers": []
            }
            
        # 模拟获取投资组合的当前价值和历史表现 - 实际需要对接数据接口
        try:
            portfolio_data = self._fetch_portfolio_performance(portfolio)
        except Exception as e:
            logger.error(f"获取投资组合表现数据失败: {e}")
            return {
                "total_value": None,
                "daily_return": None,
                "total_return": None,
                "volatility": None,
                "sharpe_ratio": None,
                "top_performers": [],
                "underperformers": [],
                "error": str(e)
            }
            
        if not portfolio_data:
            logger.warning("未能获取到投资组合表现数据")
            return {
                "total_value": None,
                "daily_return": None,
                "total_return": None,
                "volatility": None,
                "sharpe_ratio": None,
                "top_performers": [],
                "underperformers": [],
                "error": "未能获取到投资组合表现数据"
            }
            
        # 计算风险指标
        risk_metrics = calculate_risk_metrics(portfolio_data)
        
        # 找出表现最佳和最差的股票 - 示例逻辑
        sorted_stocks = sorted(
            portfolio_data["stock_performance"].items(),
            key=lambda item: item[1]["daily_return"],
            reverse=True
        )
        top_performers = [code for code, perf in sorted_stocks[:3]] # 取前3
        underperformers = [code for code, perf in sorted_stocks[-3:]] # 取后3
        
        report = {
            "total_value": portfolio_data.get("total_value"),
            "daily_return": portfolio_data.get("daily_return"),
            "total_return": portfolio_data.get("total_return"),
            "volatility": risk_metrics.get("volatility"),
            "sharpe_ratio": risk_metrics.get("sharpe_ratio"),
            "max_drawdown": risk_metrics.get("max_drawdown"), # 添加最大回撤
            "top_performers": top_performers,
            "underperformers": underperformers
        }
        
        logger.info(f"投资组合监控报告生成: {report}")
        return report
        
    def _fetch_portfolio_performance(self, portfolio: Dict[str, float]) -> Dict[str, Any]:
        """
        模拟获取投资组合表现数据
        
        参数:
            portfolio: 投资组合配置 (股票代码: 权重)
            
        返回:
            包含投资组合价值、收益率、个股表现等数据的字典
        """
        logger.info("模拟获取投资组合表现数据")
        
        if not portfolio:
            logger.warning("投资组合为空，无法获取表现数据")
            return {}
            
        total_value = 1000000 # 初始投资 100万
        daily_return = 0.005 # 假设日收益率 0.5%
        total_return = 0.02 # 假设总收益率 2%
        
        stock_performance = {}
        for stock_code in portfolio.keys():
            stock_performance[stock_code] = {
                "daily_return": 0.008, # 假设个股日收益率
                "total_return": 0.03 # 假设个股总收益率
            }
            
        return {
            "total_value": total_value,
            "daily_return": daily_return,
            "total_return": total_return,
            "stock_performance": stock_performance
        }